﻿using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using IssueVision.Data.Web;
using IssueVision.Common;
using MVVMPlugin;

namespace IssueVision.ViewModel
{
    [ExportPlugin(ViewModelTypes.NewIssueViewModel, PluginType.ViewModel)]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class NewIssueViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IIssueVisionModel _issueVisionModel;
        #endregion "Private Data Members"

        #region "Constructor"
        public NewIssueViewModel()
        {
            _issueVisionModel = PluginCatalogService.Container.GetExportedValue<IIssueVisionModel>();

            // set up event handling
            _issueVisionModel.SaveChangesComplete += _issueVisionModel_SaveChangesComplete;
            _issueVisionModel.PropertyChanged += _issueVisionModel_PropertyChanged;

            // initiate a new issue
            CurrentIssue = _issueVisionModel.AddNewIssue();
            AppMessages.EditIssueMessage.Send(CurrentIssue);
        }
        #endregion "Constructor"

        #region "ICleanup interface implementation"
        public override void Cleanup()
        {
            if (_issueVisionModel != null)
            {
                // unregister all events
                _issueVisionModel.SaveChangesComplete -= _issueVisionModel_SaveChangesComplete;
                _issueVisionModel.PropertyChanged -= _issueVisionModel_PropertyChanged;
                _issueVisionModel = null;
            }
            // set properties back to null
            CurrentIssue = null;
            // unregister any messages for this ViewModel
            base.Cleanup();
        }
        #endregion "ICleanup interface implementation"

        #region "Public Properties"

        private Issue _currentIssue;

        public Issue CurrentIssue
        {
            get { return _currentIssue; }
            private set
            {
                if (!ReferenceEquals(_currentIssue, value))
                {
                    _currentIssue = value;
                    RaisePropertyChanged("CurrentIssue");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand _submitChangeCommand;

        public RelayCommand SubmitChangeCommand
        {
            get
            {
                if (_submitChangeCommand == null)
                {
                    _submitChangeCommand = new RelayCommand(
                        OnSubmitChangeCommand,
                        () => (_issueVisionModel != null) && (_issueVisionModel.HasChanges));
                }
                return _submitChangeCommand;
            }
        }

        private void OnSubmitChangeCommand()
        {
            try
            {
                if (!_issueVisionModel.IsBusy)
                {
                    if (CurrentIssue != null)
                    {
                        // this should trigger validation even if the Title is not changed and is null
                        if (string.IsNullOrWhiteSpace(CurrentIssue.Title))
                            CurrentIssue.Title = string.Empty;

                        // if status is Open, AssignedToID should be null
                        if (CurrentIssue.StatusID == IssueVisionServiceConstant.OpenStatusID)
                        {
                            CurrentIssue.AssignedToID = null;
                        }
                        // set ResolutionDate and ResolvedByID based on ResolutionID
                        if (CurrentIssue.ResolutionID == null || CurrentIssue.ResolutionID == 0)
                        {
                            CurrentIssue.ResolutionDate = null;
                            CurrentIssue.ResolvedByID = null;
                        }
                        else
                        {
                            if (CurrentIssue.ResolutionDate == null)
                                CurrentIssue.ResolutionDate = DateTime.Now;
                            if (CurrentIssue.ResolvedByID == null)
                                CurrentIssue.ResolvedByID = WebContext.Current.User.Identity.Name;
                        }

                        if (CurrentIssue.TryValidateObject()
                            && CurrentIssue.TryValidateProperty("IssueID")
                            && CurrentIssue.TryValidateProperty("Title"))
                        {
                            _issueVisionModel.SaveChangesAsync();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand _cancelChangeCommand;

        public RelayCommand CancelChangeCommand
        {
            get
            {
                if (_cancelChangeCommand == null)
                {
                    _cancelChangeCommand = new RelayCommand(
                        OnCancelChangeCommand,
                        () => (_issueVisionModel != null) && (_issueVisionModel.HasChanges));
                }
                return _cancelChangeCommand;
            }
        }

        private void OnCancelChangeCommand()
        {
            try
            {
                var theResult = MessageBoxResult.Cancel;

                if (!_issueVisionModel.IsBusy)
                {
                    // ask to confirm canceling this new issue first
                    var dialogMessage = new DialogMessage(
                        this,
                        CommonResources.CancelCurrentIssueMessageBoxText,
                        s => theResult = s)
                    {
                        Button = MessageBoxButton.OKCancel,
                        Caption = CommonResources.ConfirmMessageBoxCaption
                    };

                    AppMessages.PleaseConfirmMessage.Send(dialogMessage);

                    if (theResult == MessageBoxResult.OK)
                    {
                        // if confirmed, cancel this issue
                        _issueVisionModel.RejectChanges();
                        // initiate a new issue again
                        CurrentIssue = _issueVisionModel.AddNewIssue();
                        AppMessages.EditIssueMessage.Send(CurrentIssue);
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        private void _issueVisionModel_SaveChangesComplete(object sender, SubmitOperationEventArgs e)
        {
            if (!e.HasError)
            {
                // notify user of the new issue ID
                foreach (Entity entity in e.SubmitOp.ChangeSet.AddedEntities)
                {
                    var addedIssue = entity as Issue;
                    if (addedIssue != null)
                    {
                        // notify user of the new issue ID
                        var dialogMessage = new DialogMessage(
                                    this,
                                    CommonResources.NewIssueCreatedText + addedIssue.IssueID,
                                    null)
                        {
                            Button = MessageBoxButton.OK,
                            Caption = CommonResources.NewIssueCreatedCaption
                        };

                        AppMessages.StatusUpdateMessage.Send(dialogMessage);
                    }
                }
                // save is successful, start another new issue
                CurrentIssue = _issueVisionModel.AddNewIssue();
                AppMessages.EditIssueMessage.Send(CurrentIssue);
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("HasChanges"))
            {
                SubmitChangeCommand.RaiseCanExecuteChanged();
                CancelChangeCommand.RaiseCanExecuteChanged();
            }
        }
        
        #endregion "Private Methods"
    }
}